package com.shop.loan.util;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.crypto.digest.MD5;
import cn.hutool.crypto.symmetric.AES;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.shop.loan.model.common.Constant;
import com.shop.loan.model.entity.LoanOrderBillByMybatis;
import com.shop.loan.model.entity.LoanOrderByMybatis;
import com.shop.loan.model.entity.SettingByMybatis;
import com.shop.loan.redis.RedisCache;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import xyz.erupt.upms.util.IpUtil;

import javax.annotation.Resource;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

@Slf4j
@Component
public class Util {

    @Resource
    RedisCache redisCache;

    private static String aesKey = "RPAONCkWMnqgVrTWp23xrS==";

    public static String prefixDel = "--del--";

    public static String GetErrorDetails(Exception ex) {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        PrintStream pout = new PrintStream(out);
        ex.printStackTrace(pout);
        String ret = new String(out.toByteArray());
        pout.close();
        try {
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
            ret = e.toString();
        }
        return ret;
    }

    /**
     * 校验内容是否存在危险字符
     *
     * @param content
     * @return
     */
    public static boolean checkContent(String requestPath, String content) {
        if (content == null) {
            return false;
        }
        if (requestPath.contains(Constant.appPrefex)) {
            if(content.contains("<") || content.contains(">")){
                return true;
            }
        }
        return false;
    }


    /**
     * 将驼峰命名转_命名
     *
     * @param param
     * @return
     */
    public static String camelToUnderline(String param) {
        String UNDERLINE = "_";
        if (param == null || "".equals(param.trim())) {
            return "";
        }
        int len = param.length();
        StringBuilder sb = new StringBuilder(len);
        for (int i = 0; i < len; i++) {
            char c = param.charAt(i);
            if (Character.isUpperCase(c)) {
                sb.append(UNDERLINE);
                sb.append(Character.toLowerCase(c));
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }


    /**
     * 记录请求日志
     *
     * @param requestPath
     * @param httpServletRequest
     * @param startTime
     */
    public JSONObject logParam(String requestPath, HttpServletRequest httpServletRequest, long startTime) {
        JSONObject headJs = new JSONObject();
        Enumeration<String> head_enumeration = httpServletRequest.getHeaderNames();
        while (head_enumeration.hasMoreElements()) {
            String key = head_enumeration.nextElement();
            headJs.put(key, httpServletRequest.getHeader(key));
        }

        JSONObject paramJs = new JSONObject();
        Enumeration<String> enumeration = httpServletRequest.getParameterNames();
        while (enumeration.hasMoreElements()) {
            String name = enumeration.nextElement();
            paramJs.put(name, httpServletRequest.getParameter(name));
        }
        //密码参数不打印
        if (paramJs.containsKey("password")) {
            paramJs.put("password", "*******");
        }
        if (paramJs.containsKey("opPassword")) {
            paramJs.put("opPassword", "*******");
        }
        if (paramJs.toJSONString().length() <= 2048) {
            log.info("收到请求:{} 请求头:{} 请求参数:{} 【IP】:{} 时间标识:{}", requestPath, JSON.toJSONString(headJs),
                    JSON.toJSONString(paramJs), IpUtil.getIpAddr(httpServletRequest), startTime);
        } else {
            log.info("收到请求:{} 请求头:{} 【IP】:{} 时间标识:{}", requestPath, JSON.toJSONString(headJs), IpUtil.getIpAddr(httpServletRequest), startTime);
        }
        httpServletRequest.setAttribute(Constant.ATTRIBUTES_TIME_KEY, startTime);
        if (!requestPath.contains("identity/update")) {
            httpServletRequest.setAttribute(Constant.ATTRIBUTES_PARAM_KEY, paramJs);
//            httpServletRequest.setAttribute(Constant.ATTRIBUTES_HEAD_PARAM_KEY, headJs);
        }
        return paramJs;
    }

    public String getHeadValue(String key) {
        HttpServletRequest httpServletRequest = RequestUtil.getRequest();
        JSONObject paramJs = (JSONObject) httpServletRequest.getAttribute(Constant.ATTRIBUTES_HEAD_PARAM_KEY);
        return paramJs.getString(key);
    }

    /**
     * 根据对应的yke获取请求参数中的值
     *
     * @param key
     * @param index
     * @return
     */
    public String getSearchParam(String key, int index) {
        /**
         *
         * {
         *     "condition":"
         *     [
         *     {"value":{"name":"丁迪朝","id":"2"},"key":"rentalUser"},
         *     {"value":{"name":"随机","id":"1"},"key":"business"},
         *     {"value":{"name":"erupt","id":"1"},"key":"serviceUser"}
         *     ]",
         *     "pageIndex":"1",
         *     "pageSize":"10",
         *     "sort":""
         * }
         *
         */
        HttpServletRequest httpServletRequest = RequestUtil.getRequest();
        JSONObject paramJs = (JSONObject) httpServletRequest.getAttribute(Constant.ATTRIBUTES_PARAM_KEY);
        if (paramJs == null) {
            return null;
        }
        if (paramJs.containsKey("condition")) {
            JSONArray jsonArray = paramJs.getJSONArray("condition");
            for (int i = 0; i < jsonArray.size(); i++) {
                String itemStr = jsonArray.getString(i);
                JSONObject itemJs = JSON.parseObject(itemStr);
                if (itemJs.containsKey("key") && itemJs.getString("key").trim().equals(key)) {
                    String value = itemJs.getString("value");
                    if (!StringUtils.hasLength(value)) {
                        continue;
                    }
                    if (JSON.isValidArray(value) && (key.contains("Time") || key.contains("searchDay") || key.contains("zhiMaScore") || key.contains("age"))) {
                        JSONArray values = JSON.parseArray(value);
                        if (values.size() >= (index + 1)) {
                            return values.getString(index);
                        }
                    } else if ("rentalUser".equals(key) || "business".equals(key) || "serviceUser".equals(key)
                            || "channel".equals(key) || "authServiceUser".equals(key) || "afterServiceUser".equals(key)
                            || "overdueServiceUser".equals(key) || "loanServiceUser".equals(key) || "collectionServiceUser".equals(key)) {

                        JSONObject jsonObject = JSON.parseObject(value);
                        if (jsonObject != null && jsonObject.containsKey("id")) {
                            return jsonObject.getString("id");
                        }
                    } else {
                        return value;
                    }
                }
            }
        }
        if (("pageIndex".equals(key) && paramJs.containsKey("pageIndex")) || ("pageSize".equals(key) && paramJs.containsKey("pageSize"))) {
            return paramJs.getString(key);
        }
        return null;
    }


    /**
     * 姓名脱敏
     *
     * @param name
     * @return
     */
    public static String desensitizedName(String name) {
        String resultName = null;
        if (name.length() == 1) {
            //张 -> 张
            resultName = name;
        }
        if (name.length() == 2) {
            //张三 -> 张*
            resultName = name.replaceFirst(name.substring(1), "*");
        }
        if (name.length() > 2) {
            //张三丰 -> 张*丰
            resultName = name.replaceFirst(name.substring(1, name.length() - 1), "*");
        }
        return resultName;
    }


    /**
     * 姓名脱敏
     *
     * @param name
     * @return
     */
    public static String DesensitizedName(String name) {
        if (!StringUtils.hasLength(name)) {
            return name;
        }
        return DesensitizedUtil.chineseName(name);
    }

    /**
     * 身份证号码脱敏
     *
     * @param idCardNum
     * @return
     */
    public static String DesensitizedIdCardNum(String idCardNum) {
        if (!StringUtils.hasLength(idCardNum)) {
            return idCardNum;
        }
        return DesensitizedUtil.idCardNum(idCardNum, 3, 4);
    }


    /**
     * 银行卡脱敏
     *
     * @param bankCardNo
     * @return
     */
    public static String DesensitizedBankNo(String bankCardNo) {
        if (!StringUtils.hasLength(bankCardNo)) {
            return bankCardNo;
        }
        return DesensitizedUtil.bankCard(bankCardNo);
    }


    /**
     * 手机号码脱敏
     *
     * @param mobile
     * @return
     */
    public static String DesensitizedMobile(String mobile) {
        if (!StringUtils.hasLength(mobile)) {
            return mobile;
        }
        return DesensitizedUtil.mobilePhone(mobile);
    }


    /**
     * 邮箱格式校验
     *
     * @param emailAddress
     * @return
     */
    public static boolean validateEmailFormat(String emailAddress) {
        // 定义邮箱格式的正则表达式
        String regex = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$";

        // 使用正则表达式进行匹配
        boolean isMatch = emailAddress.matches(regex);

        return isMatch;
    }


    /**
     * 获取密文
     *
     * @param dataStr
     * @return
     */
    public static String getAesStr(String dataStr) {
        AES aes = new AES(new SecretKeySpec(aesKey.getBytes(), "AES"));
        return aes.encryptBase64(dataStr);
    }

    /**
     * 获取aes明文
     *
     * @param encrypt
     * @return
     */
    public static String getAesDesStr(String encrypt) {
        try {
            if (!StringUtils.hasText(encrypt)) {
                return null;
            }
            AES aes = new AES(new SecretKeySpec(aesKey.getBytes(), "AES"));
            return aes.decryptStr(encrypt);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 生成商户的订单号
     *
     * @return
     */
    public static String getOutTradeNo() {
        return MD5.create().digestHex(UUID.randomUUID().toString());
    }

    public static String getOrderId() {
        return "88" + DateUtil.format(new Date(), "yyyyMMddHHmmss");
    }

    public String getUserId(Long userId) {
        SettingByMybatis settingByMybatis = redisCache.getSetting(false);
        if (settingByMybatis == null || settingByMybatis.getPrefix() == null) {
            return "Empty_" + userId;
        }
        return settingByMybatis.getPrefix() + "_" + userId;
    }


    public static String getUsName(String mobile) {
        return "us" + mobile.substring(mobile.length() - 4);
    }

    public static String getBigMoney(BigDecimal money) {
        return NumberToChinese.toChineseUpper(money);
    }


    /**
     * 利息计算
     *
     * @param money
     * @param yearRate
     * @param day
     * @return
     */
    public static BigDecimal getRateMoney(BigDecimal money, BigDecimal yearRate, Integer day) {
        BigDecimal yearMoney = money.multiply(yearRate).divide(BigDecimal.valueOf(100), RoundingMode.DOWN);
        return yearMoney.divide(BigDecimal.valueOf(365), 2, RoundingMode.DOWN).multiply(BigDecimal.valueOf(day));
    }


    /**
     * 获取借条还款时间
     *
     * @param startDate
     * @param periodDay
     * @return
     */
    public static Date getEndDate(Date startDate, Integer period, Integer periodDay) {
        return DateUtil.offsetDay(startDate, period * periodDay);
    }

    /**
     * 获取每期还款信息
     *
     * @param loanOrderByMybatis
     * @return
     */
    public static List<LoanOrderBillByMybatis> getPeriodList(LoanOrderByMybatis loanOrderByMybatis) {
        BigDecimal periodMoney = loanOrderByMybatis.getMoney().divide(BigDecimal.valueOf(loanOrderByMybatis.getPeriod()), 2, RoundingMode.DOWN);
        BigDecimal periodRateMoney = loanOrderByMybatis.getRateMoney().divide(BigDecimal.valueOf(loanOrderByMybatis.getPeriod()), 2, RoundingMode.DOWN);

        Date startDate = new Date();
        List<LoanOrderBillByMybatis> periodList = new ArrayList<>();
        for (int i = 1; i <= loanOrderByMybatis.getPeriod(); i++) {
            if (i == 1) {
                startDate = DateUtil.offsetDay(startDate, loanOrderByMybatis.getPeriodDay() - 1);
            } else {
                startDate = DateUtil.offsetDay(startDate, loanOrderByMybatis.getPeriodDay());
            }

            LoanOrderBillByMybatis signOrderBillByMybatis = new LoanOrderBillByMybatis();
            signOrderBillByMybatis.setOrderId(loanOrderByMybatis.getId());
            signOrderBillByMybatis.setMoney(periodMoney);
            signOrderBillByMybatis.setRateMoney(periodRateMoney);
            signOrderBillByMybatis.setPeriod(i);
            signOrderBillByMybatis.setTotalPeriod(loanOrderByMybatis.getPeriod());
            signOrderBillByMybatis.setPayStatus(false);
            signOrderBillByMybatis.setOverdueStatus(true);
            signOrderBillByMybatis.setOverdueFine(BigDecimal.ZERO);
            signOrderBillByMybatis.setPayTime(startDate);
            signOrderBillByMybatis.setPayTimeStr(DateUtil.formatDate(startDate));
            signOrderBillByMybatis.setPayMoney(BigDecimal.ZERO);
            signOrderBillByMybatis.setDiscountsMoney(BigDecimal.ZERO);
            signOrderBillByMybatis.setOverdueDay(0);
            signOrderBillByMybatis.setUnPayMoney(getUnPayMoney(signOrderBillByMybatis));

            periodList.add(signOrderBillByMybatis);
        }
        return periodList;
    }
//
//    /**
//     * 今日是否到期日
//     *
//     * @param loanEnd
//     * @param signOrderBillByMybatisList
//     * @return
//     */
//    public static boolean isTodayExpire(Date loanEnd, List<SignOrderBillByMybatis> signOrderBillByMybatisList) {
//        boolean todayExpire = false;
//        if (loanEnd != null) {
//            todayExpire = DateUtil.isSameDay(loanEnd, new Date());
//        }
//        if (signOrderBillByMybatisList != null) {
//            for (SignOrderBillByMybatis signOrderBillByMybatis : signOrderBillByMybatisList) {
//                if (!signOrderBillByMybatis.getPayStatus() && DateUtil.isSameDay(signOrderBillByMybatis.getPayTime(), new Date())) {
//                    signOrderBillByMybatis.setTodayExpire(true);
//                    todayExpire = true;
//                } else {
//                    signOrderBillByMybatis.setTodayExpire(false);
//                }
//            }
//        }
//        return todayExpire;
//    }


    public static Boolean checkIsSettle(LoanOrderBillByMybatis loanOrderBillByMybatis) {
        //账单金额+利息+滞纳金 <= 已还本息+已还商品金额+减免本息
        if (loanOrderBillByMybatis.getMoney().add(loanOrderBillByMybatis.getRateMoney()).add(loanOrderBillByMybatis.getOverdueFine()).compareTo(loanOrderBillByMybatis.getPayMoney().add(loanOrderBillByMybatis.getDiscountsMoney())) <= 0) {
            return true;
        }
        return false;
    }


    public static BigDecimal getUnPayMoney(LoanOrderBillByMybatis loanOrderBillByMybatis) {
        return loanOrderBillByMybatis.getMoney().add(loanOrderBillByMybatis.getRateMoney()).add(loanOrderBillByMybatis.getOverdueFine()).subtract(loanOrderBillByMybatis.getPayMoney().add(loanOrderBillByMybatis.getDiscountsMoney()));
    }


    /**
     * 未还本息
     *
     * @param
     * @return
     */
    public static BigDecimal getUnPayMoneyByPi(BigDecimal money, BigDecimal rateMoney, BigDecimal overdueFine, BigDecimal payMoney, BigDecimal discountsMoney) {
        return money.add(rateMoney).add(overdueFine).subtract(payMoney.add(discountsMoney));
    }

    /**
     * 未还本息
     *
     * @param loanOrderBillByMybatis
     * @return
     */
    public static BigDecimal getUnPayMoneyByPi(LoanOrderBillByMybatis loanOrderBillByMybatis) {
        return loanOrderBillByMybatis.getMoney().add(loanOrderBillByMybatis.getRateMoney()).add(loanOrderBillByMybatis.getOverdueFine()).subtract(loanOrderBillByMybatis.getPayMoney().add(loanOrderBillByMybatis.getDiscountsMoney()));
    }

    /**
     * 未还商品金额
     *
     * @return
     */
    public static BigDecimal getUnPayMoneyByGoods(BigDecimal shopMoney, BigDecimal payMoneyByGoods) {
        return shopMoney.subtract(payMoneyByGoods);
    }

}
